From: Ian.Campbell@xensource.com Date: Fri, 21 Apr 2006 16:19:31 +0000 (+0100) Subject: Linux support for sysenter/exit on x86_32. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~16117^2~33 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/success//%22http:/www.example.com/cgi/success/?a=commitdiff_plain;h=dadf394db4b56349c0aea6f72e406e5d3e2e80ac;p=xen.git Linux support for sysenter/exit on x86_32. This support is only active when supervisor_mode_kernel is enabled in the Xen build (and when the hardware supports sysenter). Signed-off-by: Ian Campbell --- diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/entry-xen.S b/linux-2.6-xen-sparse/arch/i386/kernel/entry-xen.S index 78ad19ef2b..770d2e1fb4 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/entry-xen.S +++ b/linux-2.6-xen-sparse/arch/i386/kernel/entry-xen.S @@ -239,7 +239,7 @@ sysenter_past_esp: jae syscall_badsys call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) - cli + DISABLE_INTERRUPTS movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx jne syscall_exit_work @@ -247,8 +247,23 @@ sysenter_past_esp: movl EIP(%esp), %edx movl OLDESP(%esp), %ecx xorl %ebp,%ebp +#ifdef CONFIG_XEN + __ENABLE_INTERRUPTS +sysexit_scrit: /**** START OF SYSEXIT CRITICAL REGION ****/ + __TEST_PENDING + jnz 14f # process more events if necessary... + movl ESI(%esp), %esi + sysexit +14: __DISABLE_INTERRUPTS +sysexit_ecrit: /**** END OF SYSEXIT CRITICAL REGION ****/ + push %esp + call evtchn_do_upcall + add $4,%esp + jmp ret_from_intr +#else sti sysexit +#endif /* !CONFIG_XEN */ # system call handler stub @@ -530,6 +545,11 @@ error_code: # So, on entry to the handler we detect whether we interrupted an # existing activation in its critical region -- if so, we pop the current # activation and restart the handler using the previous one. +# +# The sysexit critical region is slightly different. sysexit +# atomically removes the entire stack frame. If we interrupt in the +# critical region we know that the entire frame is present and correct +# so we can simply throw away the new one. ENTRY(hypervisor_callback) pushl %eax SAVE_ALL @@ -538,6 +558,11 @@ ENTRY(hypervisor_callback) jb 11f cmpl $ecrit,%eax jb critical_region_fixup + cmpl $sysexit_scrit,%eax + jb 11f + cmpl $sysexit_ecrit,%eax + ja 11f + addl $0x34,%esp # Remove cs...ebx from stack frame. 11: push %esp call evtchn_do_upcall add $4,%esp diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c b/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c index 32e44f0f01..844c87e78c 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c @@ -20,6 +20,10 @@ #include #include +#ifdef CONFIG_XEN +#include +#endif + extern asmlinkage void sysenter_entry(void); void enable_sep_cpu(void) @@ -54,6 +58,18 @@ int __init sysenter_setup(void) { syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); +#ifdef CONFIG_XEN + if (boot_cpu_has(X86_FEATURE_SEP)) { + struct callback_register sysenter = { + .type = CALLBACKTYPE_sysenter, + .address = { __KERNEL_CS, (unsigned long)sysenter_entry }, + }; + + if (HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter) < 0) + clear_bit(X86_FEATURE_SEP, boot_cpu_data.x86_capability); + } +#endif + if (boot_cpu_has(X86_FEATURE_SEP)) { memcpy(syscall_page, &vsyscall_sysenter_start,